/**
 * Copyright 2018 asiainfo Inc.
 **/
package com.myz.app.shiro.session;

import org.apache.shiro.session.mgt.SimpleSession;

import java.io.Serializable;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

/**
 * 每次访问都会多次调用SessionDAO的doUpdate方法，来更新Redis上数据，
 * 更新的字段只有LastAccessTime（最后一次访问时间），由于会话失效是由Redis数据过期实现的，
 * 这个字段意义不大，为了减少对Redis的访问，降低网络压力，实现自己的Session，在SimpleSession上套一层，
 * 增加一个标识位，如果Session除lastAccessTime以外其它字段修改，就标识一下，
 * 只有标识为修改的才可以通过doUpdate访问Redis，否则直接返回。这也是上面SessionDao中doUpdate中逻辑判断的意义
 *
 * Session Attribute
 * DefaultSubjectContext.PRINCIPALS_SESSION_KEY 保存 principal
 * DefaultSubjectContext.AUTHENTICATED_SESSION_KEY 保存 boolean是否登陆
 *
 * @author maoyz on 2018/6/18
 * @version: v1.0
 */
public class AbstractSession extends SimpleSession implements Serializable {

  /**
   * 除lastAccessTime以外其他字段发生改变时为true
   */
  private boolean isChanged;

  public AbstractSession() {
    super();
    this.setChanged(true);
  }

  public AbstractSession(String host) {
    super(host);
    this.setChanged(true);
  }

  @Override
  public void setId(Serializable id) {
    this.setChanged(true);
    super.setId(id);
  }

  /**
   * 开始时间戳
   *
   * @param startTimestamp
   */
  @Override
  public void setStartTimestamp(Date startTimestamp) {
    super.setStartTimestamp(startTimestamp);
    this.setChanged(true);
  }

  /**
   * 结束时间戳
   *
   * @param stopTimestamp
   */
  @Override
  public void setStopTimestamp(Date stopTimestamp) {
    super.setStopTimestamp(stopTimestamp);
    this.setChanged(true);
  }

  @Override
  public void setLastAccessTime(Date lastAccessTime) {
    if (lastAccessTime != null) {
      long now = getLastAccessTime().getTime();
      long last = lastAccessTime.getTime();

      // todo 如果3s内访问 则不更新session,否则需要更新远端过期时间
      if ((now - last) / 1000 > 3) {

      }

    }
    super.setLastAccessTime(lastAccessTime);
  }

  /**
   * 设置过期时间
   *
   * @param expired
   */
  @Override
  public void setExpired(boolean expired) {
    super.setExpired(expired);
    this.setChanged(true);
  }

  /**
   * 设置超时
   *
   * @param timeout
   */
  @Override
  public void setTimeout(long timeout) {
    super.setTimeout(timeout);
    this.setChanged(true);
  }

  /**
   * 设置主机
   *
   * @param host
   */
  @Override
  public void setHost(String host) {
    super.setHost(host);
    this.setChanged(true);
  }

  @Override
  public void setAttributes(Map<Object, Object> attributes) {
    super.setAttributes(attributes);
    this.setChanged(true);
  }

  /**
   * 防止过于频繁的保存
   *
   * @param key
   * @param value
   */
  @Override
  public void setAttribute(Object key, Object value) {
    Object val = this.getAttribute(key);
    //
    if (val != null && Objects.equals(val, value)) {
      return;
    }
    super.setAttribute(key, value);
    this.setChanged(true);
  }

  @Override
  public Object removeAttribute(Object key) {
    this.setChanged(true);
    return super.removeAttribute(key);
  }

  public boolean isChanged() {
    return isChanged;
  }

  public void setChanged(boolean changed) {
    isChanged = changed;
  }
}
